import dayjs from 'dayjs';
import l_debounce from 'lodash/debounce';
import l_throttle from 'lodash/throttle';
import l_compact from 'lodash/compact';
import l_concat from 'lodash/concat';
import l_uniq from 'lodash/uniq';
import l_random from 'lodash/random';
import l_find from 'lodash/find';
import l_cloneDeep from 'lodash/cloneDeep';

import { getCountDwon, checkTime, formatTime } from './timeHelper';

/**
 * dayjs文档：https://day.js.org/docs/zh-CN/installation/installation
 * @param {number} time 时间戳，毫秒
 * @param {string} [format] 转换格式
 * YYYY	四位数的年份
 * MM	01-12	月份，两位数
 * DD	01-31	月份里的一天，两位数
 * HH	00-23	小时，两位数
 * mm	00-59	分钟，两位数
 * ss	00-59	秒 两位数
 * 示例：parseTime(1599910244844); // => 2020-09-12 19:30
 */
export function parseTime(time, format = 'YYYY-MM-DD HH:mm') {
  return dayjs(time).format(format);
}

/**时间转换
 * @param {时间戳(单位毫秒)} timestamp
 *  规则
 *  (t= 当前时间 - 最后一条消息发送/接收时间)
 *  1、t<1min时，显示“刚刚”
 *  2、1min <t <60min  ,显示“t分钟前”
 *  3、t>=60 且最后一条消息时间与当前时间属于同一个自然日，显示“时：分：秒”
 *  4、最后一条消息发生在上个自然日，显示“昨天 时：分：秒”
 *  5、其他，显示“年/月/日  时：分：秒”
 *
 * 示例：transformTime(Date.now() - 2000)) // => '刚刚
 *      transformTime(Date.now() - 1000 * 60 * 10)) // => '10分钟前'
 */
export function transformTime(timestamp) {
  return formatTime(timestamp);
}

/**
 * 创建一个 debounced（防抖动）函数，该函数会从上一次被调用后，延迟 wait 毫秒后调用 func 方法。
 * @param {Function} func 要防抖动的函数。
 * @param {number} [wait] 需要延迟的毫秒数。
 * @param {Object} [options] 选项对象
 * [options.leading=false] (boolean): 指定在延迟开始前调用。
 * [options.maxWait] (number): 设置 func 允许被延迟的最大值。
 * [options.trailing=true] (boolean): 指定在延迟结束后调用。
 * 使用方式1：
 * methods: {
 *   addOne: _debounce(() => {
 *     console.log(1);
 *   }, 500),
 * },
 * 文档：https://www.lodashjs.com/docs/latest#_debouncefunc-wait0-options
 */
export function _debounce(func, wait = 200, options = {}) {
  return l_debounce(func, wait, options);
}

/**
 * 创建一个节流函数，在 wait 秒内最多执行 func 一次的函数。
 * @param {Function} func 要节流的函数。
 * @param {number} [wait] 需要节流的毫秒。
 * @param {Object} [options] 选项对象
 * [options.leading=true] (boolean): 指定调用在节流开始前。
 * [options.trailing=true] (boolean): 指定调用在节流结束后。
 * 文档：https://www.lodashjs.com/docs/latest#_throttlefunc-wait0-options
 */
export function _throttle(func, wait = 200, options = {}) {
  return l_throttle(func, wait, options);
}

/** 创建一个新数组，包含原数组中所有的非假值元素。例如false, null, 0, "", undefined, 和 NaN 都是被认为是“假值”。
 * @param {Array} arr 待处理的数组
 * 返回值:(Array): 返回过滤掉假值的新数组。
 * 文档：https://www.lodashjs.com/docs/latest#_compactarray
 */
export function _compact(arr) {
  return l_compact(arr);
}

/**
 * 创建一个新数组，将array与任何数组 或 值连接在一起。
 * _concat(array, [values])
 * 参数：array (Array): 被连接的数组。
 *      [values] (...*): 连接的值。
 * 返回值： 返回连接后的新数组。
 * 示例：
 * _concat([3,4,5],2, [3], [[4]]); //  => [3, 4, 5, 2, 3, [4]]
 * 文档：https://www.lodashjs.com/docs/latest#_concatarray-values
 */
export function _concat() {
  return l_concat(...arguments);
}

/**创建一个去重后的array数组副本
 * @param {array} arr 要检查的数组
 * 返回值:  返回新的去重后的数组。
 * 文档：https://www.lodashjs.com/docs/latest#_uniqarray
 */
export function _uniq(arr) {
  return l_uniq(arr);
}

/**产生一个包括 lower 与 upper 之间的数。 如果只提供一个参数返回一个0到提供数之间的数。 如果 floating 设为 true，或者 lower 或 upper 是浮点数，结果返回浮点数。
 * 参数：
 * [lower=0] (number): 下限。
 * [upper=1] (number): 上限。
 * [floating] (boolean): 指定是否返回浮点数。
 * 返回  (number): 返回随机数。
 * 示例：
 * _random(1, 10) // => 3
 * 文档：https://www.lodashjs.com/docs/latest#_randomlower0-upper1-floating
 */
export function _random() {
  return l_random(...arguments);
}

/**遍历 collection（集合）元素，返回 predicate（断言函数）第一个返回真值的第一个元素。
 * 调用方式：_find(collection, [predicate=_.identity], [fromIndex=0])
 *参数：
 * collection (Array|Object): 一个用来迭代的集合。
 * [predicate=_.identity] (Array|Function|Object|string): 每次迭代调用的函数。
 * [fromIndex=0] (number): 开始搜索的索引位置。
 * 返回：
 * 返回匹配元素，否则返回 undefined
 *示例1在数组中查找：
 *  _find([{name:'mary',age:12},{name:'lisa',age:34}], ({ age }) => age>10); // => {name:'mary',age:12}
 *示例2在对象中查找：
 *  _find({'mary':{name:'mary',age:12},'lisa':{name:'lisa',age:34}}, ({ age }) => age>10); // => {name:'mary',age:12}
 * 文档：https://www.lodashjs.com/docs/latest#_findcollection-predicate_identity-fromindex0
 */
export function _find() {
  return l_find(...arguments);
}

/**深拷贝
 * @param {*} 要深拷贝的值
 * 返回：返回拷贝后的值
 * 示例：
 * const objects = [{ 'a': 1 }, { 'b': 2 }];
 * const deep = _.cloneDeep(objects);
 * console.log(deep[0] === objects[0]);// => false
 */
export function _cloneDeep(val) {
  return l_cloneDeep(val);
}

/**
 * 将异步api转成promise调用
 * @param {string} method 微信api名
 * @param {object} options 微信api参数
 */
export function transAsyncToPro(method, options, proxy = uni) {
  return new Promise((resolve, reject) => {
    proxy[method]({
      ...options,
      success: resolve,
      fail: reject,
    });
  });
}

/**增加图片地址前后缀,用阿里云oss技术压缩图片，
 * 阿里云文档：https://help.aliyun.com/document_detail/44686.html?spm=a2c4g.11186623.6.1674.6c02c1f6et36mf
 * @param {string} path 图片地址
 * @param {Object} resize 图片缩放，具体参数：https://help.aliyun.com/document_detail/44688.html?spm=a2c4g.11186623.6.1677.6487e849mXNfjp
 * @param {Object} quality 质量转换，具体参数：https://help.aliyun.com/document_detail/44705.html?spm=a2c4g.11186623.6.1694.6ba4c1f6444g1G
 * @param {string} format 格式转换，具体参数：https://help.aliyun.com/document_detail/44703.html?spm=a2c4g.11186623.6.1692.ec9ee849pwpyOj
 * 示例1：imCompress('file/201809/12/20180912153727944421610.png') // => https://res.shiguangkey.com/file/201809/12/20180912153727944421610.png?x-oss-process=image/resize,l_4096/quality,Q_50/format,jpg
 * 示例2: imCompress('https://res.shiguangkey.com/res/images/default.png') // => https://res.shiguangkey.com/res/images/default.png?x-oss-process=image/resize,l_4096/quality,Q_50/format,jpg
 */
export function imgCompress(path, resize = { l: 4096 }, quality = { Q: 50 }, format = 'jpg') {
  // 需传入绝对路径
  if (!path) return '';
  let url = path;
  if (!/^https?:\/\//.test(path)) {
    url = `https://res.shiguangkey.com/${path}`;
  }
  // 路径中包含'?x-oss-process',或者是图片是gif类型，则不进行压缩
  if (url.includes('?x-oss-process') || /\.gif$/i.test(url)) return url;
  // resize:图片缩放参数,quality:质量变换参数，format：格式转换参数
  const _resize = Object.keys(resize).reduce((pre, cur) => `${pre},${cur}_${resize[cur]}`, '');
  const _quality = Object.keys(quality).reduce((pre, cur) => `${pre},${cur}_${quality[cur]}`, '');
  const press = `?x-oss-process=image/resize${_resize}/quality${_quality}/format,${format}`;
  return url + press;
}

/**
 * 在数字超过某一临界值时，转换单位
 * @param {Number} num 需要转换的数字
 * @param {Number} bound 边界  默认值：1e4
 * @param {Number} toFixed 保留几位小数 默认值：2
 * @param {String} unit 单位 默认值：w
 * 示例：transformBigNumber(11000) //=>1.10w
 */
export function transformBigNumber(num, bound = 1e4, toFixed = 2, unit = 'w') {
  return num > bound ? `${(num / bound).toFixed(toFixed)}${unit}` : num;
}

/**
 * 检查值是否为空
 * @param {*} data 需要检查的值
 * 如果为空返回 true，否则返回 false。
 */
export function isEmpty(data) {
  return data === '' || data === undefined || data === null;
}

/**
 * 倒计时：天时分秒
 * @param {Number} leftTime  时间差
 * 示例： countDwonByDay(96391631); // => { day: '01', hour: '02', minute: '46', second: '31' }
 */
export function countDwonByDay(leftTime) {
  return getCountDwon(leftTime);
}

/**
 * 倒计时：时分秒
 * @param {Number} leftTime  时间差
 * 示例：countDwonByHour(86391631) // => { hour: '23', minute: '59', second: '51' }
 */
export function countDwonByHour(leftTime) {
  const { day, hour, minute, second } = getCountDwon(leftTime);
  return {
    hour: checkTime(+day * 24 + +hour),
    minute,
    second,
  };
}

/**
 * 前置补0
 * @param {*} value 要填充的值
 * @param {number} num 保留位数 默认值：2
 * 示例: addZeroPrefix(9)  // => 09
 *       addZeroPrefix(3, 3) // => 003
 */
export function addZeroPrefix(value, n = 2) {
  if (`${value}`.length > n) return value;
  const prefix = Array(n + 1).join(0);
  return (prefix + value).slice(-n);
}

//   parseTime, // 时间格式转换
//   transformTime, // 时间转换，'刚刚'，t分钟前，时：分：秒，昨天 时：分：秒，年/月/日  时：分：秒
//   _debounce, // 创建一个防抖动函数
//   _throttle, // 创建一个节流函数
//   _compact, //  创建一个新数组，包含原数组中所有的非假值元素。
//   _concat, // 创建一个新数组，将array与任何数组 或 值连接在一起。
//   _uniq, // 创建一个去重后的array数组副本
//   _random, // 产生一个包括 lower 与 upper 之间的数。
//   _find, // 遍历集合（Array|Object）元素，返回第一个返回真值的第一个元素
//   _cloneDeep, // 深拷贝
//   isEmpty, // 检查值是否为空
//   transAsyncToPro, // 将异步api转成promise调用
//   imgCompress, // 使用阿里云oss技术压缩图片，
//   transformBigNumber, // 在数字超过某一临界值时，转换单位
//   countDwonByDay, // 倒计时，XX天XX时XX分XX秒
//   countDwonByHour, // 倒计时，XX时XX分XX秒
//   addZeroPrefix, // 前置补0, 9 => 09,
//   webViewCall, // app交互
